
package com.rt.schedulenew.utils.coder;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.*;

public final class SecurityCoderUtil
{
    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final Random RANDOM;
    public static final byte[] ENCRYPT_KEY;
    public static final byte[] TICKET_ENCRYPT_KEY;
    public static final byte[] LICENSE_ENCRYPT_KEY;
    public static final String CHARSET = "UTF-8";
    public static final String FIELD_SIGN = "sign";
    public static final String FIELD_SIGN_TYPE = "signType";
    
    private SecurityCoderUtil() {
    }
    
    public static final byte[] decryptBASE64(final String key) {
        try {
            final String base64Str = key;
            new BASE64Coder();
            return BASE64Coder.decodeFast(base64Str);
        }
        catch (Exception e) {
            throw new RuntimeException("解密错误，错误信息：", e);
        }
    }
    
    public static final byte[] decryptBASE64Special(final String key) {
        try {
            String base64Str = key.replace('-', '+');
            base64Str = base64Str.replace('_', '/');
            switch (base64Str.length() % 4) {
                case 0: {
                    break;
                }
                case 2: {
                    base64Str += "==";
                    break;
                }
                case 3: {
                    base64Str += "=";
                    break;
                }
                default: {
                    System.err.println("Illegal base64url String!");
                    throw new RuntimeException("解密错误，错误信息：");
                }
            }
            return new BASE64Coder().decodeSpecial(base64Str);
        }
        catch (Exception e) {
            throw new RuntimeException("解密错误，错误信息：", e);
        }
    }
    
    public static final String encryptBASE64(final byte[] key) {
        try {
            new BASE64Coder();
            final String encodeBase64 = BASE64Coder.encode(key);
            return encodeBase64;
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
    }
    
    public static final String encryptBASE64Special(final byte[] key) {
        try {
            final String encodeBase64 = new BASE64Coder().encodeSpecial(key);
            String safeBase64Str = encodeBase64.replace('+', '-');
            safeBase64Str = safeBase64Str.replace('/', '_');
            safeBase64Str = safeBase64Str.split("=")[0];
            return safeBase64Str;
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
    }
    
    public static final String encryptBASE64(final String key) {
        try {
            new BASE64Coder();
            final String encodeBase64 = BASE64Coder.encode(key);
            return encodeBase64;
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
    }
    
    public static final String decryptDes(final String cryptData) {
        return decryptDes(cryptData, SecurityCoderUtil.ENCRYPT_KEY);
    }
    
    public static final String encryptDes(final String data) {
        return encryptDes(data, SecurityCoderUtil.ENCRYPT_KEY);
    }
    
    public static final String decryptDes(final String cryptData, final byte[] key) {
        String decryptedData = null;
        try {
            decryptedData = new String(DESCoder.decrypt(decryptBASE64(cryptData), key));
        }
        catch (Exception e) {
            throw new RuntimeException("解密错误，错误信息：", e);
        }
        return decryptedData;
    }
    
    public static final String decryptDesSpecial(final String cryptData, final byte[] key) {
        String decryptedData = null;
        try {
            decryptedData = new String(DESCoder.decrypt(decryptBASE64Special(cryptData), key));
        }
        catch (Exception e) {
            throw new RuntimeException("解密错误，错误信息：", e);
        }
        return decryptedData;
    }
    
    public static final String encryptDes(final String data, final byte[] key) {
        String encryptedData = null;
        try {
            encryptedData = encryptBASE64(DESCoder.encrypt(data.getBytes(), key));
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
        return encryptedData;
    }
    
    public static final String encryptDesSpecial(final String data, final byte[] key) {
        String encryptedData = null;
        try {
            encryptedData = encryptBASE64Special(DESCoder.encrypt(data.getBytes(), key));
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
        return encryptedData;
    }
    
    public static final String encryptMd5(final String strSrc) {
        String outString = null;
        try {
            outString = encryptBASE64(MDCoder.encodeMD5(strSrc.getBytes("UTF-8")));
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
        return outString;
    }
    
    public static final String encryptMd5Special(final String strSrc) {
        String outString = null;
        try {
            outString = encryptBASE64Special(MDCoder.encodeMD5(strSrc.getBytes("UTF-8")));
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
        return outString;
    }
    
    public static final String encryptMd5Base(final String strSrc) {
        String outString = null;
        try {
            final byte[] strByte = MDCoder.encodeMD5(strSrc.getBytes("UTF-8"));
            final BigInteger integer = new BigInteger(1, strByte);
            outString = integer.toString(16);
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
        return outString;
    }
    
    public static final String encryptSHA(final String data) {
        try {
            return encryptBASE64(SHACoder.encodeSHA256(data.getBytes("UTF-8")));
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
    }
    
    public static final String encryptHMAC(final String data) {
        return encryptHMAC(data, SecurityCoderUtil.ENCRYPT_KEY);
    }
    
    public static final String encryptHMAC(final String data, final byte[] key) {
        try {
            return encryptBASE64(HmacCoder.encodeHmacSHA512(data.getBytes("UTF-8"), key));
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
    }
    
    public static final String encryptHMAC256(final String data, final byte[] key) {
        try {
            return encryptBASE64(HmacCoder.encodeHmacSHA256(data.getBytes("UTF-8"), key));
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
    }
    
    public static final String signRSA(final String data, final String privateKey) {
        try {
            return encryptBASE64(RSACoder.sign(data.getBytes("UTF-8"), decryptBASE64(privateKey)));
        }
        catch (Exception e) {
            throw new RuntimeException("签名错误，错误信息：", e);
        }
    }
    
    public static final boolean verifyRSA(final String data, final String publicKey, final String sign) {
        try {
            return RSACoder.verify(data.getBytes("UTF-8"), decryptBASE64(publicKey), decryptBASE64(sign));
        }
        catch (Exception e) {
            throw new RuntimeException("验签错误，错误信息：", e);
        }
    }
    
    public static final Map<String, String> getRSAKeyPair() {
        Map<String, Object> key = new HashMap<String, Object>();
        try {
            key = RSACoder.initKey();
            final String privateKey = encryptBASE64(RSACoder.getPrivateKey(key));
            final String publicKey = encryptBASE64(RSACoder.getPublicKey(key));
            final Map<String, String> rsaKey = new HashMap<String, String>();
            rsaKey.put("privateKey", privateKey);
            rsaKey.put("publicKey", publicKey);
            return rsaKey;
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("获取RSA密钥对错误，错误信息：", e);
        }
    }
    
    public static final String encryptRSAPublic(final String data, final String publicKey) {
        try {
            return encryptBASE64(RSACoder.encryptByPublicKey(data.getBytes("UTF-8"), decryptBASE64(publicKey)));
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
    }
    
    public static final String encryptRSAPrivate(final String data, final String privateKey) {
        try {
            return encryptBASE64(RSACoder.encryptByPrivateKey(data.getBytes("UTF-8"), decryptBASE64(privateKey)));
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
    }
    
    public static final String decryptRSAPublic(final String cryptData, final String publicKey) {
        try {
            return new String(RSACoder.decryptByPublicKey(decryptBASE64(cryptData), decryptBASE64(publicKey)));
        }
        catch (Exception e) {
            throw new RuntimeException("解密错误，错误信息：", e);
        }
    }
    
    public static final String decryptRSAPrivate(final String cryptData, final String privateKey) {
        try {
            return new String(RSACoder.decryptByPrivateKey(decryptBASE64(cryptData), decryptBASE64(privateKey)));
        }
        catch (Exception e) {
            throw new RuntimeException("解密错误，错误信息：", e);
        }
    }
    
    public static final String generateAesKey() {
        final String key = getRandom(16);
        return key;
    }
    
    public static final String encryptAES(final String data, final String password) {
        try {
            return AESCoder.encryptByCBC(data, password);
        }
        catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
    }
    
    public static final String decryptAES(final String data, final String password) {
        try {
            return AESCoder.decryptByCBC(data, password);
        }
        catch (Exception e) {
            throw new RuntimeException("解密错误，错误信息：", e);
        }
    }
    
    public static String generateSignature(final Map<String, String> data, final String key) throws Exception {
        return generateSignature(data, key, "MD5");
    }
    
    public static String generateSignature(final Map<String, String> data, final String key, final String signType) throws Exception {
        final Set<String> keySet = data.keySet();
        final String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        final StringBuilder sb = new StringBuilder();
        for (final String k : keyArray) {
            if (!k.equals("sign")) {
                if (!k.equals("signType")) {
                    if (data.get(k).trim().length() > 0) {
                        sb.append(k).append("=").append(data.get(k).trim()).append("&");
                    }
                }
            }
        }
        String str = sb.toString();
        if (str.endsWith("&")) {
            str = str.substring(0, str.length() - 1);
        }
        if (signType == null || "MD5".equals(signType)) {
            return MDCoder.MD5(str).toUpperCase();
        }
        if ("SHA256".equals(signType)) {
            return SHACoder.HMACSHA256(str, key);
        }
        throw new Exception(String.format("Invalid signType: %s", signType));
    }
    
    public static boolean isSignatureValid(final Map<String, String> data, final String key, final String signType) throws Exception {
        if (!data.containsKey("sign")) {
            return false;
        }
        final String sign = data.get("sign");
        return generateSignature(data, key, signType).equals(sign);
    }
    
    public static String getRandom(int count) {
        if (count == 0) {
            count = 32;
        }
        final char[] nonceChars = new char[count];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(SecurityCoderUtil.RANDOM.nextInt("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".length()));
        }
        return new String(nonceChars);
    }
    
    public static void main(final String[] args) throws Exception {
        final String nonceStr = getRandom(6);
        System.out.println("nonceStr:" + nonceStr);
        final String password = encryptMd5Special(nonceStr);
        System.out.println("password:" + password);
    }
    
    static {
        RANDOM = new SecureRandom();
        ENCRYPT_KEY = new byte[] { -81, 0, 105, 7, -32, 26, -49, 88 };
        TICKET_ENCRYPT_KEY = new byte[] { -81, 0, 105, 8, -32, 20, -49, 86 };
        LICENSE_ENCRYPT_KEY = new byte[] { -81, 6, 105, 3, -32, 27, -44, 60 };
    }
}
